import { Card, CardType, Equipment, BasicCard } from "../cardsystem/card"
import { GameManager } from "../gamesystem/gameManager"
import { CardTypeRequestProxyFactory, CardUsingEventHandler, CardUsingEventWrapper, DefaultRequestProxyFactory, ResponseHandlerProxy } from './handlers'
import { Jiu, Sha } from "../cardsystem/basicCard"
import { MinusOneHourse, PlusOneHourse } from "../cardsystem/equipments/horses"
import { Shield } from "../cardsystem/equipments/shields"
import { Weapons } from "../cardsystem/equipments/weapons"
import { DelayBrilliantness } from "../cardsystem/brilliantness/delay"
import { JudgeAreaController } from "./areas/judgeAreaController"
import { PhaseController } from "./phase"
import { HandCardAreas } from "./areas/handCardAreas"
import { EquipmentAreas } from "./areas/EquipmentAreas"
import { WaitForPushCardEvent } from "@/store/reactiveStore"
import { BaseSmartBehavior, BaseUserBehavior, BehaviorStragy, PickCardOptions } from "../strategies/BaseSmartBehavior"

const DefaultPromise = <T>(t:T) => new Promise<T>((resolve) => resolve(t));




export interface Player {
    name: string,
    handCardAreas: HandCardAreas
    equipmentAreas: EquipmentAreas
    judgeAreaController: JudgeAreaController,
    gameManager: GameManager,
    phaseController: PhaseController,
    maxHP: number,
    currentHP: number,
    currentPickCardNumber: number,
    behaviorStragy: BehaviorStragy

    /**
     * 到玩家回合
     * @returns 
     */
    turnrun: () => Promise<void>,

    /**
     * 判断是否有牌
     * @param cls BasicCard: 手牌 Equipment: 装备牌 Weapons: 武器
     */
    hasCards(cls?: string): boolean,

    reduceHP(n: number): boolean,
    recoverHP(n: number): boolean,
    isBeingDead(): boolean,
    dead(): boolean,

    /**
     * 计算攻击距离 = 攻击距离
     */
    calAttackDist(): number,

    /**
     * 从玩家上创建事件代理
     * @param card 
     */
    createCardUsingEventHandler<T extends Card>(sourceHandler: CardUsingEventHandler<T>): CardUsingEventHandler<T>,

    registerSourceCardUsingHandler<T extends Card>(p:ResponseHandlerProxy<T>):void,

    removeSourceCardUsingHandler<T extends Card>(p:ResponseHandlerProxy<T>):void,

    registerRequestCardProxy(p:CardTypeRequestProxyFactory):void,

    removeRequestCardProxy(p:CardTypeRequestProxyFactory):void,

    equals: (p: Player) => boolean
    

}

export class UserPlayer implements  Player {
    name: string
    handCardAreas: HandCardAreas
    equipmentAreas: EquipmentAreas
    judgeAreaController: JudgeAreaController
    phaseController: PhaseController
    gameManager: GameManager
    maxHP: number
    currentHP: number
    currentPickCardNumber: number
    behaviorStragy: BehaviorStragy

    sourceCardEventHandlers:  Map<string, ResponseHandlerProxy<Card>>
    requestCardEventHandlers: Map<string, CardTypeRequestProxyFactory>

    constructor(name: string, gameManager: GameManager) {
        this.name = name
        this.gameManager = gameManager
        this.maxHP = 4
        this.currentHP = 4
        this.currentPickCardNumber = 0
        this.phaseController = new PhaseController(this)
        this.handCardAreas = new HandCardAreas(this)
        this.equipmentAreas = new EquipmentAreas(this)
        this.judgeAreaController = new JudgeAreaController(this)
        this.behaviorStragy = new BaseUserBehavior()
        this.sourceCardEventHandlers = new Map()
        this.requestCardEventHandlers = new Map()
        this.registerRequestCardProxy(DefaultRequestProxyFactory)
    }

    resetPlayer() {
        this.currentPickCardNumber = 0
    }

    calAttackDist(): number {
        return this.equipmentAreas.attackDistances
    }

    hasCards(cls: string|undefined): boolean {
        const hasEquipments = this.equipmentAreas.hasEquipment()
        const hasHandCards = this.handCardAreas.hasHandCards()
        if (cls == Equipment.name) {
            return hasEquipments
        } else if (cls == BasicCard.name) {
            return hasHandCards
        } else if (cls == Weapons.name) {
            return this.equipmentAreas.hasWeapon()
        } else if (cls == DelayBrilliantness.name) {
            return this.judgeAreaController.hasCards()
        } else  {
            return hasEquipments || hasHandCards
        }

    }

    registerSourceCardUsingHandler<T extends Card>(p:ResponseHandlerProxy<T>):void {
        this.sourceCardEventHandlers.set(p.constructor.name, p)
    }

    removeSourceCardUsingHandler<T extends Card>(p:ResponseHandlerProxy<T> ):void {
        this.sourceCardEventHandlers.delete(p.constructor.name)
    }
    registerRequestCardProxy(p:CardTypeRequestProxyFactory):void {
        this.requestCardEventHandlers.set(p.name, p)
    }

    removeRequestCardProxy(p:CardTypeRequestProxyFactory):void {
        this.requestCardEventHandlers.delete(p.name)
    }

    createCardUsingEventHandler<T extends Card>(sourceHandler: CardUsingEventHandler<T>): CardUsingEventHandler<T> {
        let res = sourceHandler
        const sourceCard = sourceHandler.card
        const sourcePlayer = sourceCard.cardProperties.source
        const targetPlayer = sourceCard.cardProperties.target
        // card.source.createCardUsingEventHandler 对原player代理
        if(sourcePlayer && this.equals(sourcePlayer)) {
            for(const h of this.sourceCardEventHandlers.values()) {
                if (h.shouldApply(res)) {
                    res = h.apply(res) as CardUsingEventHandler<T>
                }
            }
        }
        // card.target.createCardUsingEventHandler 对目标player 代理
        if (targetPlayer && this.equals(targetPlayer)) {
            const reverseHandlerProxys:CardTypeRequestProxyFactory[] = []
            for (const f of this.requestCardEventHandlers.values()) {
                reverseHandlerProxys.push(f)
            }
            for (const f of reverseHandlerProxys.reverse()) {
                const h = f.createResponseHandlerProxy(this)
                if (h.shouldApply(res)) {
                    res = h.apply(res) as CardUsingEventHandler<T>
                }
            }
            
        }

        return res
    }

    reduceHP(n: number): boolean {
        this.currentHP = this.currentHP - n
        return this.currentHP <= 0
    }

    recoverHP(n: number): boolean {
        if (this.currentHP + n <= this.maxHP) {
            this.currentHP = this.currentHP + n
            return true
        }
        
        return false
    }

    isBeingDead() {
        return this.currentHP <= 0
    }

    dead(): boolean {
        this.gameManager.removePlayer(this)
        this.resetPlayer()
        return true
    }

    async turnrun() {
        const iter = this.phaseController.iterator()
        for(const phaseHandler of iter) {
            if (!phaseHandler.shouldSkip(this)) {
                await phaseHandler.execute(this)
            }
            phaseHandler.endPhase(this)
        }
    }

    equals(p: Player) {
        return this.name == p.name
    }

}


/**
 * 带智能决策 player，单机版玩家实现
 */
export class SmartPlayer extends UserPlayer {

    constructor(name: string, gameManager: GameManager) {
        super(name, gameManager)
        this.behaviorStragy = new BaseSmartBehavior()
    }

}
